package bitcat.chuenyee.utils

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper

object JsonUtil {
    private val mapper: ObjectMapper = jacksonObjectMapper()

    /**
     * 比对 beforeValue 和 afterValue，生成差异 Map
     * @param beforeValue JSON 字符串 (数组或对象)
     * @param afterValue JSON 字符串 (数组或对象)
     * @return Map<String, Map<String, Any?>> 形式的 diff
     */
    fun diff(beforeValue: String?, afterValue: String?): Map<String, Map<String, Any?>> {
        if (beforeValue.isNullOrBlank() && afterValue.isNullOrBlank()) return emptyMap()

        val beforeNode: JsonNode? = beforeValue?.let { mapper.readTree(it) }
        val afterNode: JsonNode? = afterValue?.let { mapper.readTree(it) }

        val diffs = mutableMapOf<String, Map<String, Any?>>()
        compareNodes("", beforeNode, afterNode, diffs)
        return diffs
    }

    private fun compareNodes(
        path: String,
        beforeNode: JsonNode?,
        afterNode: JsonNode?,
        diffs: MutableMap<String, Map<String, Any?>>
    ) {
        when {
            beforeNode == null && afterNode != null -> {
                diffs[path] = mapOf("before" to null, "after" to nodeToValue(afterNode))
            }
            beforeNode != null && afterNode == null -> {
                diffs[path] = mapOf("before" to nodeToValue(beforeNode), "after" to null)
            }
            beforeNode != null && afterNode != null -> {
                if (beforeNode.isObject && afterNode.isObject) {
                    // 遍历所有字段
                    val fieldNames = (beforeNode.fieldNames().asSequence() + afterNode.fieldNames().asSequence()).toSet()
                    for (field in fieldNames) {
                        val childPath = if (path.isEmpty()) field else "$path.$field"
                        compareNodes(childPath, beforeNode.get(field), afterNode.get(field), diffs)
                    }
                } else if (beforeNode.isArray && afterNode.isArray) {
                    // 简单处理：按索引比对
                    val maxSize = maxOf(beforeNode.size(), afterNode.size())
                    for (i in 0 until maxSize) {
                        val childPath = "$path[$i]"
                        compareNodes(childPath, beforeNode.get(i), afterNode.get(i), diffs)
                    }
                } else {
                    val beforeVal = nodeToValue(beforeNode)
                    val afterVal = nodeToValue(afterNode)
                    if (beforeVal != afterVal) {
                        diffs[path] = mapOf("before" to beforeVal, "after" to afterVal)
                    }
                }
            }
        }
    }

    private fun nodeToValue(node: JsonNode?): Any? {
        if (node == null || node.isNull) return null
        return when {
            node.isTextual -> node.asText()
            node.isNumber -> node.numberValue()
            node.isBoolean -> node.asBoolean()
            node.isObject || node.isArray -> node.toString() // 保持 JSON 字符串
            else -> node.asText()
        }
    }
}